/*******************************************************************************
 * Copyright 2007 Vidar Svansson
 *     
 * This file is part of JAdapter.
 * 
 * JAdapter is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * JAdapter is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with JAdapter.  If not, see <http://www.gnu.org/licenses/>.
 *******************************************************************************/


package org.jadapter.registry;

import org.jadapter.Adapter;
import org.jadapter.AdapterFactory;
import org.jadapter.func.Lambda;

/** Static class for the component API.
 * Mainly for testing and simple uses/demonstrations.
 * 
 * It uses {@link SimpleComponentRegistry} internally but it can be
 * override by registering a custom {@link ComponentRegistry} 
 * using {@link #setComponentRegistry(ComponentRegistry)}.
 * 
 * @author Vidar Svansson
 * 
 * @since 1.0
 *
 */
public class Components {

    private static ComponentRegistry registry;


    /** Get an instance of a given type */
    public static <T> T get(Class<T> type) {
        return getComponentRegistry().get(type);
    }
    
    
    /** Get an instance of a given type given some context type
     * 
     * @param <T> The return type
     * @param type The return type
     * @param context the type of the context
     * @return an instance of the required type or null
     */
    public static <T> T get(Class<T> type, Class<?> context){
        return getComponentRegistry().get(type, context); 
    }     
    
    /*** Factories ***/
    
    /** Create an instance of the given type */
    public static <T> T create(Class<T> type) {
        return getComponentRegistry().create(type);
    }    
    
    /** Create an instance of the give type for a context type */
    public static <T,C> T create(Class<T> type, Class<C> context) {
        return getComponentRegistry().create(type, context);
    }
    
    /*** Adapters ***/
    
    /** Get an instance of the given some context object */
    @SuppressWarnings("unchecked")
    public static <T> T get(Class<T> type, Object context) {
        return getComponentRegistry().adapt(type, context);
    }    
    
    public static <T> T get(Class<T> type, Object context, String name) {
        return getComponentRegistry().adapt(type, context, name);
    }
    
    
    
    /**** registration API ****/
    
    
    @SuppressWarnings("unchecked")
    public static <I,C> void registerAdapter(
            Class<I> provides, 
            Class<? extends Adapter<? extends I, ? extends C>> adapter, 
            Class<C> adaptable) {
        getComponentRegistry().register(provides, adapter, adaptable);
    }
    

    
    /** Register a configured adapter */
    public static <I,C> void register(AdapterFactory<I,C> adapter) {
        getComponentRegistry().register(adapter);
    }
    

    /** Register an object to serve as a singleton utility */
    public static void register(Object utility){
        getComponentRegistry().register(utility);
    }

    /** Register an object to serve as a singleton utility for a specific interface
     * TODO 
     * @param type the type to provide
     * @param utility the instance singleton
     */
    public static void register(Class<?> type, Object utility) {
        getComponentRegistry().register(type, utility);
    }	

    /** Register a factory class for a type 
     * 
     * @param <I> the generic type provided by the factory class. 
     * @param type the provided type.
     * @param implementation implementing the type.
     */
    public static <I> void register(Class<I> type, 
            Class<? extends I> implementation) {
        
        getComponentRegistry().register(type, implementation);
    }    
    
    public static <I,C> void register(Class<I> type, 
            I utility, Class<C> context) {
        
        getComponentRegistry().register(type, utility, context);
    }

    public static <I,C> void register(
            Class<I> provides, 
            Class<? extends I> adapter, 
            Class<C> adaptable) {
        getComponentRegistry().register(provides, adapter, adaptable);
    } 
    
    
    public static <I,C> void register(
            Class<I> provides,
            final Lambda<I,C> adapter,
            Class<C> context){
        
        getComponentRegistry().register(provides, adapter, context);       
        
    }
    
    @SuppressWarnings("unchecked")
    public static <I,C> void register(
            Class<I> provides, 
            Adapter adapter, 
            Class<C> adaptable) {
        getComponentRegistry().register(provides, adapter, adaptable);
    }


    public static ComponentRegistry getComponentRegistry() {
        if (registry == null) registry = new SimpleComponentRegistry();
        return registry;
    }


    public static void setComponentRegistry(ComponentRegistry registry) {
        Components.registry = registry;
    }   
    
    
    public static void destroy() { registry = null; }
        
}
